<?php

namespace App\Core;

use Lcobucci\Clock\FrozenClock;
use Lcobucci\JWT\Configuration;
use Lcobucci\JWT\Signer\Hmac\Sha256;
use Lcobucci\JWT\Signer\Key\InMemory;
use Lcobucci\JWT\Validation\Constraint\SignedWith;
use Lcobucci\JWT\Validation\Constraint\ValidAt;

class JWT
{

    /**
     * 获取令牌配置
     *
     * @return Configuration
     */
    private function getConfig(): Configuration
    {
        return Configuration::forSymmetricSigner(new Sha256(),
            InMemory::base64Encoded(config('system.jwt.secret'))
        );
    }

    /**
     * 获取 JWT Token
     *
     * @param array $data
     * @return string
     */
    public function getToken(array $data): string
    {
        $now = new \DateTimeImmutable();
        // 初始化配置
        $config = $this->getConfig();
        // 令牌有效期
        $token = $config->builder()->issuedAt($now)->expiresAt($now->modify('+1 hour'));

        // 自定义参数
        foreach ($data as $name => $value) {
            $token->withClaim($name, $value);
        }

        return (string)$token->getToken(
            $config->signer(),
            $config->signingKey()
        );
    }

    /**
     * 解析 JWT Token
     *
     * @param string $jwt
     * @return array|false
     */
    public function parseToken(string $jwt)
    {
        $now = new \DateTimeImmutable();
        // 初始化配置
        $config = $this->getConfig();

        // 解析令牌
        try {
            $token = $config->parser()->parse($jwt);
        } catch (\InvalidArgumentException $e) {
            return false;
        }

        // 验证令牌
        if (!$config->validator()->validate($token,
            new SignedWith(
                $config->signer(),
                $config->signingKey()
            ),
            new ValidAt(
                new FrozenClock($now)
            )
        )) {
            return false;
        }

        return $token->claims()->all();
    }

    /**
     * Create a new JWT instance.
     *
     * @param mixed ...$parameters
     * @return static
     */
    public static function instance(...$parameters): JWT
    {
        return new static(...$parameters);
    }
}
